#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
# @version: v1.0
# @author : wlis
# @Email : 19688513@qq.com
# @Project : g-carbon-bio
# @File : stock_data_manager.py
# @Software: PyCharm
# @time: 2025/2/4 18:53
# @description :  股票列表-A股  接口: stock_info_a_code_name 个股信息查询 接口: stock_individual_info_em
"""
import os
import time
import logging
import pandas as pd
import akshare as ak
import requests

from service.csv_help import CSVHelp
from service.models.stock_data import StockData

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')


class StockDataManager:
    def __init__(self, file_name='stock_data.csv'):
        """
        初始化 StockDataManager 类
        :param file_name: 保存数据的 CSV 文件名
        """
        self.csv_helper = CSVHelp()  # CSV 操作工具类
        self.max_attempts = 3  # 最大重试次数
        self.stock_data_list = []  # 存储股票数据的列表
        self.failed_stocks = []  # 存储失败的股票信息（使用字典记录）
        self.file_name = file_name  # 保存数据的文件名

    def fetch_esg_data(self):
        """
        从新浪财经获取 ESG 数据
        :return: 包含 ESG 数据的 DataFrame
        """
        big_df = pd.DataFrame()  # 初始化一个空的 DataFrame
        p = 1  # 初始化页码

        while True:
            # 构建请求 URL
            url = f"https://global.finance.sina.com.cn/api/openapi.php/EsgService.getZdEsgStocks?p={p}&num=20000"
            r = requests.get(url)
            data_json = r.json()

            # 检查返回的数据是否为空
            if not data_json["result"]["data"]["data"]:
                print(f"没有更多数据可获取，当前页码: {p}")
                break  # 当没有更多数据时，退出循环

            # 将返回的数据转换为 DataFrame
            temp_df = pd.DataFrame(data_json["result"]["data"]["data"])

            # 重命名列
            temp_df.rename(
                columns={
                    "ticker": "股票代码",
                    "esg_score": "ESG评分",
                    "report_date": "评分日期",
                    "environmental_score": "环境总评",
                    "social_score": "社会责任总评",
                    "governance_score": "治理总评",
                },
                inplace=True,
            )

            # 选择需要的列
            temp_df = temp_df[
                [
                    "股票代码",
                    "ESG评分",
                    "环境总评",
                    "社会责任总评",
                    "治理总评",
                    "评分日期",
                ]
            ]

            # 将评分日期转换为日期格式
            temp_df["评分日期"] = pd.to_datetime(temp_df["评分日期"], errors="coerce").dt.date

            # 将临时 DataFrame 添加到总的 DataFrame 中
            big_df = pd.concat([big_df, temp_df], ignore_index=True)

            # 增加页码
            p += 1

        return big_df

    def fetch_stock_data(self):
        """
        获取股票数据并保存到 CSV 文件
        """
        start_time = time.time()  # 记录开始时间
        logging.info("开始获取股票数据...")

        # 获取 A 股股票代码和名称
        start_time_code_name = time.time()  # 记录开始时间
        stock_info_a_code_name_df = ak.stock_info_a_code_name()
        end_time_code_name = time.time()  # 记录结束时间

        logging.info(f"获取 A 股股票代码和名称耗时: {end_time_code_name - start_time_code_name:.2f} 秒")

        # 获取 ESG 数据
        start_time_esg = time.time()  # 记录开始时间
        stock_esg_zd_sina_df = self.fetch_esg_data()
        end_time_esg = time.time()  # 记录结束时间

        logging.info(f"获取 ESG 数据耗时: {end_time_esg - start_time_esg:.2f} 秒")

        # 去掉 ESG 数据中的后缀
        stock_esg_zd_sina_df['股票代码'] = stock_esg_zd_sina_df['股票代码'].str.replace('.SH', '').str.replace('.SZ',
                                                                                                               '')
        # 遍历每一只股票
        for _, row in stock_info_a_code_name_df.iterrows():
            code = row['code'].replace('.SH', '').replace('.SZ', '')  # 去掉后缀 .SH 和 .SZ
            name = row['name']
            logging.info(f"股票代码：{code}，股票名称：{name}")

            # 查找包含该股票代码的 ESG 评分信息
            esg_row = stock_esg_zd_sina_df[stock_esg_zd_sina_df['股票代码'].str.contains(code, na=False)]

            if esg_row.empty:
                logging.warning(f"未找到 {code} 的 ESG 评分信息，使用默认值。")
                rating_agency = '-'
                rating = '-'
                rating_quarter = '-'
            else:
                rating_agency = '秩鼎'  # 假设评级机构为秩鼎
                rating = esg_row.iloc[0]['ESG评分']
                rating_quarter = esg_row.iloc[0]['评分日期']

            # 调用获取个股信息的函数
            self.get_individual_stock_info(code, rating_agency, rating, rating_quarter)

        # 判断 failed_stocks 是否存在数据，如果存在则进行重试
        if self.failed_stocks:
            logging.info("开始重试获取失败的股票信息...")
            for stock_info in self.failed_stocks:
                self.get_individual_stock_info(stock_info['code'], stock_info['rating_agency'],
                                                stock_info['rating'], stock_info['rating_quarter'], wait_time=5)

        # 保存数据到 CSV
        self.save_data_to_csv()

        end_time = time.time()  # 记录结束时间
        logging.info(f"股票数据获取完成，耗时 {end_time - start_time:.2f} 秒")

    def get_individual_stock_info(self, code, rating_agency, rating, rating_quarter, wait_time = 1):
        """
        获取个股的详细信息
        :param code: 股票代码
        :param rating_agency: 评级机构
        :param rating: 评级
        :param rating_quarter: 评级季度
        """
        attempt = 0
        while attempt < self.max_attempts:
            try:
                # 根据 wait_time 的值决定是否延迟
                if wait_time > 0:
                    time.sleep(wait_time)
                start_time = time.time()  # 记录开始时间
                # 获取个股信息
                stock_info_df = ak.stock_individual_info_em(symbol=code)
                stock_info_dict = stock_info_df.set_index('item')['value'].to_dict()

                # 创建 StockData 对象
                stock_data = StockData(
                    stock_code=stock_info_dict.get('股票代码'),
                    stock_name=stock_info_dict.get('股票简称'),
                    total_market_value=stock_info_dict.get('总市值'),
                    circulating_market_value=stock_info_dict.get('流通市值'),
                    industry=stock_info_dict.get('行业'),
                    listing_date=stock_info_dict.get('上市时间'),
                    total_shares=stock_info_dict.get('总股本'),
                    circulating_shares=stock_info_dict.get('流通股'),
                    rating_agency=rating_agency,
                    rating=rating,
                    rating_quarter=rating_quarter,
                )

                # 将股票数据添加到列表中
                self.stock_data_list.append(stock_data)
                logging.info(f"成功获取 {code} 的个股信息")
                end_time = time.time()  # 记录结束时间
                logging.info(f"获取 {code} 的个股信息成功，耗时 {end_time - start_time:.2f} 秒")
                return
            except Exception as e:
                logging.error(f"Error 获取个股信息 {code} 第 {attempt + 1} 次尝试: {str(e)}")
                self.failed_stocks.append({
                    'code': code,
                    'rating_agency': rating_agency,
                    'rating': rating,
                    'rating_quarter': rating_quarter,
                    'error': str(e)
                })  # 记录失败的股票信息
                attempt += 1
                time.sleep(5)

        logging.warning(f"最大尝试次数 {self.max_attempts} 达到，跳过股票 {code}")

    def save_data_to_csv(self):
        """
        将股票数据保存到 CSV 文件
        """
        start_time = time.time()  # 记录开始时间
        # 构建数据字典
        data = {
            'stock_code': [stock.stock_code for stock in self.stock_data_list],
            'stock_name': [stock.stock_name for stock in self.stock_data_list],
            'total_market_value': [stock.total_market_value for stock in self.stock_data_list],
            'circulating_market_value': [stock.circulating_market_value for stock in self.stock_data_list],
            'industry': [stock.industry for stock in self.stock_data_list],
            'listing_date': [stock.listing_date for stock in self.stock_data_list],
            'total_shares': [stock.total_shares for stock in self.stock_data_list],
            'circulating_shares': [stock.circulating_shares for stock in self.stock_data_list],
            'rating_agency': [stock.rating_agency for stock in self.stock_data_list],
            'rating': [stock.rating for stock in self.stock_data_list],
            'rating_quarter': [stock.rating_quarter for stock in self.stock_data_list],
        }
        # 将数据转换为 DataFrame
        df = pd.DataFrame(data)
        # 保存到 CSV 文件
        df.to_csv(os.path.join(self.csv_helper.folder_path, self.file_name), index=False)
        end_time = time.time()  # 记录结束时间
        logging.info(f"股票数据成功保存到 {self.file_name}，耗时 {end_time - start_time:.2f} 秒")

    def read_stock_data(self):
        """
        从 CSV 文件读取股票数据
        :return: 股票数据列表
        """
        start_time = time.time()  # 记录开始时间
        file_path = os.path.join(self.csv_helper.folder_path, self.file_name)

        if not os.path.exists(file_path):
            logging.warning(f"文件 {self.file_name} 不存在，无法读取数据。")
            return []

        # 读取 CSV 文件
        df = self.csv_helper.read_csv(self.file_name)
        stock_data_list = []
        # 将每一行数据转换为 StockData 对象
        for _, row in df.iterrows():
            stock_data = StockData(
                stock_code=row['stock_code'],
                stock_name=row['stock_name'],
                total_market_value=row['total_market_value'],
                circulating_market_value=row['circulating_market_value'],
                industry=row['industry'],
                listing_date=row['listing_date'],
                total_shares=row['total_shares'],
                circulating_shares=row['circulating_shares'],
                rating_agency=row['rating_agency'],
                rating=row['rating'],
                rating_quarter=row['rating_quarter'],
            )
            stock_data_list.append(stock_data)

        end_time = time.time()  # 记录结束时间
        logging.info(f"从 CSV 加载数据成功，耗时 {end_time - start_time:.2f} 秒")
        return stock_data_list


# 使用示例
# if __name__ == "__main__":
#     stock_data_manager = StockDataManager()
#
#     logging.info("开始获取股票数据...")
#     stock_data_manager.fetch_stock_data()  # 获取股票数据
#
#     logging.info("从 CSV 加载数据...")
#     stock_data_list = stock_data_manager.read_stock_data()

    # 循环输出每个 StockData 对象的数据
    # if stock_data_list:
    #     for stock_data in stock_data_list:
    #         logging.info(f"股票代码: {stock_data.stock_code}, 股票名称: {stock_data.stock_name}, "
    #                      f"总市值: {stock_data.total_market_value}, 流通市值: {stock_data.circulating_market_value}, "
    #                      f"行业: {stock_data.industry}, 上市时间: {stock_data.listing_date}, "
    #                      f"总股本: {stock_data.total_shares}, 流通股: {stock_data.circulating_shares}, "
    #                      f"评级机构: {stock_data.rating_agency}, 评级: {stock_data.rating}, "
    #                      f"评级季度: {stock_data.rating_quarter}")
    # else:
    #     logging.warning("未加载任何股票数据。")

